package mint.modules.generator;

import java.util.ArrayList;
import java.util.Formatter;
import java.util.List;

import org.antlr.runtime.tree.Tree;

import mint.modules.generator.expression.ExprNode;
import mint.modules.generator.expression.Expression;
import mint.modules.generator.expression.ExpressionType;
import mint.modules.symbol.Symbol;
import mint.modules.symbol.SymbolType;
import mint.modules.symbol.VariableSymbol;
import mint.modules.type.Type;
import mint.modules.type.TypeId;

public class VariableDeclarationNode extends Scope implements MintNode {
	private String name;
	private Type type;
	private Scope parent;
	private List<String> errors;
	private int line;
	private Expression exprNode;
	private boolean enabled;
	
	public VariableDeclarationNode(Scope theParent, Tree variableTreeNode, Type theType)
	{
		super(theParent, theParent.containerClass);
		name = variableTreeNode.getText();		
		type = theType;
		parent = theParent;
		errors = new ArrayList<String>();
		line = variableTreeNode.getLine();
		enabled = false;
		if (variableTreeNode.getChildCount() > 0)
			exprNode = new ExprNode(parent, ExpressionType.Right, variableTreeNode.getChild(0));
		else
			exprNode = null;
	}
	
	public String getName()
	{
		return name;
	}
	
	public Type getType()
	{
		return type;
	}

	@Override
	public void testSemantic() {
		if (type.getTypeId() == TypeId.Object || type.getTypeId() == TypeId.ObjectArray)
		{
			Symbol symbol = parent.searchSymbol(type.getName(), getContainerClass(), false);
			
			if (symbol == null)
				errors.add(line + ": " + type.getName() + " doesn't exists on this scope");
			else
				if (symbol.getSymbolType() != SymbolType.Class)
					errors.add(line + ": " + type.getName() + " isn't a type name");
		}
		
		enabled = true;
		if(exprNode != null)
		{
			exprNode.testSemantic();			
			
			if (type.equals(Type.floatType))
				if (!(exprNode.getType().equals(Type.intType) || exprNode.getType().equals(Type.floatType)))
					errors.add(line + ": incompatible types: " + type.getCompleteName() + " and " + exprNode.getType().getCompleteName());
			else
				if (!type.equals(exprNode.getType()))
				{
					if(!exprNode.getType().equals(Type.objectNullType))
						errors.add(line + ": incompatible types: " + type.getCompleteName() + " and " + exprNode.getType().getCompleteName());
				}
		}	
	}
	
	public boolean isEnabled()
	{
		return enabled;
	}

	@Override
	public List<String> getSemanticErrors() {
		if(exprNode != null)
			errors.addAll(exprNode.getSemanticErrors());
		return errors;
	}

	@Override
	public void emit(Formatter output) {		
		if (exprNode != null)
		{
			Symbol symbol = searchSymbol(name, getContainerClass(), false);
			VariableSymbol variable = (VariableSymbol)symbol;
			
			exprNode.emit(output);
			
			if (variable.getType().equals(Type.intType) || variable.getType().equals(Type.booleanType))
			{
				output.format("istore %s\n", variable.getNumber());					
			} else if (variable.getType().equals(Type.floatType))
			{
				output.format("fstore %s\n", variable.getNumber());
			}
			else
			{
				output.format("astore %s\n", variable.getNumber());				
			}			
		}
	}

	@Override
	public int getLine() {
		return line;
	}

	@Override
	public void printSymbolTable(Formatter output, int tabSize) {}

}